package com.qingcloud.df.executor.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ZipUtil;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;
import com.qingcloud.base.constant.SystemConstant;
import com.qingcloud.base.remote.executor.ExecutorParam;
import com.qingcloud.df.executor.exception.CommException;
import com.qingcloud.df.sdk.component.config.ComponentConfig;
import com.qingcloud.df.sdk.component.config.ComponentOutputConfig;
import com.qingcloud.df.sdk.component.config.ComponentParameterConfig;
import com.qingcloud.df.sdk.component.context.ConfigManager;
import com.qingcloud.df.sdk.component.extractor.ComponentExtractor;
import com.qingcloud.df.sdk.component.utils.ComponentCommUtils;
import com.qingcloud.oss.service.OssTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

@Component
public class ConfigService {
    public static final Logger logger = LoggerFactory.getLogger(ConfigService.class);
    @Resource
    private OssTemplate ossTemplate;

    @Value("${qingcloud.executor.bucketName}")
    private String bucketName;

    public void refushConfig(List<ExecutorParam.InstanceParam> instanceContexts){
        //下载所有实例配置文件
        instanceContexts.forEach(instanceContext ->{
            try {
                receiverConfig(instanceContext);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }

    /**
     * 下载指定单个实例的配置文件
     * @param instanceContext
     * @throws Exception
     */
    public void receiverConfig(ExecutorParam.InstanceParam instanceContext)  {
        String configUrl = instanceContext.getConfigUrl();
        Integer jobId = instanceContext.getJobId();
        Integer instanceId =  instanceContext.getInstanceId();
        String  env  = instanceContext.getEnv();

        String softwareName = configUrl.substring(configUrl.lastIndexOf("/")+1, configUrl.lastIndexOf("."));
        String instanceDir = ComponentCommUtils.getCompInstWorkspace(jobId, instanceId, softwareName, env);
        FileUtil.del(instanceDir);
        String jobInstancePath = ComponentCommUtils.getJobWorkspace(jobId,env);
        //解压到指定工作目录
        downloadComponent(jobInstancePath, configUrl);
        //下载后删除历史文件
        //removeObject(configUrl);
        ConfigManager.reloadInstance(instanceId,env);
    }

    /**
     * 导入配置文件并启动整个作业
     */
    public void importJob(MultipartFile multipartFile, String env) {
        if (!"application/zip".equals(multipartFile.getContentType())) {
            //zip解压缩处理
            throw new CommException("上传的文件不是ZIP");
        }
        //保存zip
        String tmpDir = System.getProperty("java.io.tmpdir");
        String destFile = tmpDir + File.separator + "qingcloud" + File.separator + IdUtil.simpleUUID() + ".zip";
        try {
            multipartFile.transferTo(new File(destFile));
            //解析配置目录
            ZipFile zipFile = new ZipFile(destFile);
            ArrayList<? extends ZipEntry> entries = Collections.list(zipFile.entries());
            if (CollUtil.isEmpty(entries)) {
                throw new CommException(multipartFile.getName() + "文件非法");
            }
            String[] split = entries.get(0).getName().split("/");
            //删除实例旧配置
            String baseDir = ComponentCommUtils.getInstanceBaseDir(env);
            String instanceConfigDir = baseDir + split[0];
            FileUtil.del(instanceConfigDir);
            //解压到指定工作目录
            ZipUtil.unzip(destFile, baseDir);
            //重新加载所有该环境内配置文件，TODO 未来重构为加载该单一目录配置文件
            ConfigManager.reloadByEnv(env);
        } catch (IOException e) {
            throw new CommException("导入文件失败");
        }
//        Integer jobId  =  Integer.parseInt(split[0].substring(split[0].lastIndexOf("_")+1));
//        List<Integer> instanceIdList = getInstancesByJobId(jobId, env);
//        //启动实例
//        return start(instanceIdList, env);
    }

    public ComponentConfig extractBaseConfig(Integer componentId, String componentNameEn, Integer componentType, Integer runMode, String objectPath) throws CommException {
        String compWorkspace = ComponentCommUtils.getComponentWorkspace(componentId, componentNameEn)+ File.separator + componentNameEn;
        logger.debug("save component path: {}",compWorkspace);
        logger.debug("minio objectPath: {}",objectPath);
        downloadComponent(compWorkspace,objectPath);
        ComponentExtractor componentExtractor =  new ComponentExtractor(componentId, componentNameEn,runMode);
        if(componentExtractor==null){
            throw new CommException("component can not load");
        }
        ComponentConfig componentConfig = new ComponentConfig();
        componentConfig.setComponentType(componentExtractor.getComponentType());
        componentConfig.setComponentName(componentExtractor.getComponentName());
        ComponentOutputConfig outputConfig =  componentExtractor.outputConfig();
        ComponentParameterConfig parameterConfig = componentExtractor.parameterConfig();
        if(outputConfig != null) {
            componentConfig.setOutput(outputConfig.getJson());
        }
        if(parameterConfig != null) {
            componentConfig.setBase(parameterConfig.allBase());
            componentConfig.setConnection(parameterConfig.allConnection());
            componentConfig.setAdvance(parameterConfig.allAdvance());
            componentConfig.setCustom(parameterConfig.allCustom());
        }
        return componentConfig;
    }
    public ComponentConfig extractDynamicOutputConfig(Integer componentId, String componentNameEn, Integer componentType, Integer runMode, Map<String,String> paramMap, String objectPath) throws CommException {
        //组件实际Jar路径
        String compWorkspace = ComponentCommUtils.getComponentWorkspace(componentId, componentNameEn)+File.separator + componentNameEn;
        String jarPath = compWorkspace + File.separator + componentNameEn + ".jar";
        File file = new File(jarPath);
        if (!file.exists()) { //必须以组件英文名称为根目录
            downloadComponent(compWorkspace,objectPath);
        }

        ComponentExtractor componentExtractor =  new ComponentExtractor(componentId, componentNameEn,runMode);
        if(componentExtractor==null){
            throw new CommException("component can not load");
        }
        ComponentOutputConfig outputConfig =  componentExtractor.dynamicOutputConfig(paramMap);
        logger.debug("get aynamicOutputConfig info : {}",outputConfig);
        ComponentConfig componentConfig = new ComponentConfig();
        if(outputConfig != null) {
            componentConfig.setOutput(outputConfig.getJson());
        }
        return  componentConfig;
    }


    public void downloadComponent(String destFilePath, String objectPath) throws CommException {
        OutputStream out = null;
        try {
            String componentsuffix = ".zip";
            String tempFileName = UUID.randomUUID() + componentsuffix;

            File workspacePath = new File(destFilePath);
            if (!workspacePath.exists()) {
                workspacePath.mkdirs();
            }
            String filePath = destFilePath + File.separator + tempFileName;
            File tempFile = FileUtil.touch(filePath);
            out = new FileOutputStream(tempFile);

            S3Object object  = ossTemplate.getObject(bucketName,objectPath);
            S3ObjectInputStream inputStream =  object.getObjectContent();
            com.amazonaws.util.IOUtils.copy(inputStream,out);
            if (out != null){ out.close();}
            //解压组件压缩包
            if (tempFile.exists() && tempFile.canRead()) {
                ZipUtil.unzip(tempFile, workspacePath);
            }
            //删除临时压缩文件包
            FileUtil.del(tempFile);
        } catch (IOException e) {
            throw new IORuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    /**
     * 删除文件
     * @param configUrl
     */
    public void removeObject(String configUrl){
        try {
            ossTemplate.removeObject(bucketName,configUrl);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
